package com.zdya.combatdocuments.ethereum;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.zdya.combatdocuments.util.AjaxResult;
import com.zdya.combatdocuments.util.EthRPCUtil;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.logging.log4j.util.Base64Util;
import org.springframework.util.Base64Utils;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.ECKeyPair;
import org.web3j.crypto.RawTransaction;
import org.web3j.crypto.TransactionEncoder;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.DefaultBlockParameter;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.Request;
import org.web3j.protocol.core.methods.response.EthBlockNumber;
import org.web3j.protocol.core.methods.response.EthGetTransactionCount;
import org.web3j.protocol.core.methods.response.EthGetTransactionReceipt;
import org.web3j.protocol.core.methods.response.EthSendTransaction;
import org.web3j.protocol.http.HttpService;
import org.web3j.tx.ChainId;
import org.web3j.utils.Convert;
import org.web3j.utils.Numeric;

import javax.json.JsonObject;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.ServerSocket;
import java.util.*;
import java.util.concurrent.ExecutionException;

/**
 * @Author:HYZ
 * @Date:2023-6-7
 */
@Slf4j
public class EthChain {

    public static void main(String[] args) throws Exception {
        String address = "0xbd9f16c701f3fd2f7eab7e9c8575d2d03d01498d";
        String keyStore = "{\"address\":\"bd9f16c701f3fd2f7eab7e9c8575d2d03d01498d\",\"id\":\"a0261610-6b88-45bf-b357-bf3e7b809f58\",\"version\":3,\"crypto\":{\"cipher\":\"aes-128-ctr\",\"ciphertext\":\"a36dc9bf0c3627c3842f86a13e027b83765dab29597e0a6a7dcb9f930af55dc3\",\"cipherparams\":{\"iv\":\"8d761f9dd2635611078465ee5e1918a3\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":4096,\"p\":6,\"r\":8,\"salt\":\"90d8c382c37e22c40c15d91d8e2faae90a87aa40b8f4aa32f12f5f73cf4814d6\"},\"mac\":\"1b3802d89e2380d86fbed9cbbcdf431b7d6187e8d9e05fe025132a641769a2cf\"}}";

        String fromAddress = "0xb80377b5e52a16b317fd5f61e10ec0d1e8ee05e3";
        String fromkeystore = "{\"address\":\"b80377b5e52a16b317fd5f61e10ec0d1e8ee05e3\",\"id\":\"656a6015-6c53-4357-bc3b-e962d9e67879\",\"version\":3,\"crypto\":{\"cipher\":\"aes-128-ctr\",\"ciphertext\":\"06607e3e0128636c7bf9e0d8d518f451d4d5f3ed3f0f891e3d049236fc0df68f\",\"cipherparams\":{\"iv\":\"a42f13ef35debcbe81e266889a546c38\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":4096,\"p\":6,\"r\":8,\"salt\":\"a6020a1bd769e724e0113f108f7278b70eeca952e4e3887adae7bc2bc1ac5d1c\"},\"mac\":\"7959347fd7f15b93c2c65e49946074341dd52182a80035f54ba56e3c851a952c\"}}";


        String chain = "1688104090";
        String chainName = "test2022";
        String contractAddress = "0xf0e4240700e8d3cee90b662ad531d7e64c66207e";
        AjaxResult ajaxResult = null;

        String key = "hyz";
        String value = "34444";


//        ajaxResult = creatChainAndStart(chain, chainName, "hyz");

//        ajaxResult = startChain(chainName, chain,"hyz");

//        Web3j web3jUtil = Web3j.build(new HttpService("http://127.0.0.1:8545"));
//        web3jUtil.shutdown();


/*
        String reqGasLimit = "30000000";
        String reqGasPrice = "10";
        String byteCode = "608060405234801561001057600080fd5b50610c3a806100206000396000f300608060405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806353ed514314610067578063693ec85e14610092578063962939b8146100cf578063f4c84d191461010c575b600080fd5b34801561007357600080fd5b5061007c610149565b6040516100899190610b1b565b60405180910390f35b34801561009e57600080fd5b506100b960048036036100b49190810190610a0e565b6104de565b6040516100c69190610b1b565b60405180910390f35b3480156100db57600080fd5b506100f660048036036100f19190810190610a4f565b6105eb565b6040516101039190610b00565b60405180910390f35b34801561011857600080fd5b50610133600480360361012e9190810190610a4f565b6106b6565b6040516101409190610b00565b60405180910390f35b6060806000806040805190810160405280600181526020017f7b000000000000000000000000000000000000000000000000000000000000008152509250600091505b600180549050821015610494576001828154811015156101a857fe5b9060005260206000200190506101f3836040805190810160405280600181526020017f2700000000000000000000000000000000000000000000000000000000000000815250610742565b925061029883828054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561028e5780601f106102635761010080835404028352916020019161028e565b820191906000526020600020905b81548152906001019060200180831161027157829003601f168201915b5050505050610742565b92506102d9836040805190810160405280600381526020017f273a270000000000000000000000000000000000000000000000000000000000815250610742565b92506103ee83600083604051808280546001816001161561010002031660029004801561033d5780601f1061031b57610100808354040283529182019161033d565b820191906000526020600020905b815481529060010190602001808311610329575b505091505090815260200160405180910390208054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156103e45780601f106103b9576101008083540402835291602001916103e4565b820191906000526020600020905b8154815290600101906020018083116103c757829003601f168201915b5050505050610742565b925060018080549050038210156104455761043e836040805190810160405280600281526020017f272c000000000000000000000000000000000000000000000000000000000000815250610742565b9250610487565b610484836040805190810160405280600181526020017f2700000000000000000000000000000000000000000000000000000000000000815250610742565b92505b818060010192505061018c565b6104d3836040805190810160405280600181526020017f7d00000000000000000000000000000000000000000000000000000000000000815250610742565b925082935050505090565b60606000826040518082805190602001908083835b60208310151561051857805182526020820191506020810190506020830392506104f3565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405180910390208054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156105df5780601f106105b4576101008083540402835291602001916105df565b820191906000526020600020905b8154815290600101906020018083116105c257829003601f168201915b50505050509050919050565b6000816000846040518082805190602001908083835b6020831015156106265780518252602082019150602081019050602083039250610601565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020908051906020019061066c929190610913565b5060018390806001815401808255809150509060018203906000526020600020016000909192909190915090805190602001906106aa929190610913565b50506001905092915050565b6000816000846040518082805190602001908083835b6020831015156106f157805182526020820191506020810190506020830392506106cc565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405180910390209080519060200190610737929190610913565b506001905092915050565b606080606080606060008088955087945084518651016040519080825280601f01601f19166020018201604052801561078a5781602001602082028038833980820191505090505b50935083925060009150600090505b855181101561084c5785818151811015156107b057fe5b9060200101517f010000000000000000000000000000000000000000000000000000000000000090047f010000000000000000000000000000000000000000000000000000000000000002838380600101945081518110151561080f57fe5b9060200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508080600101915050610799565b600090505b845181101561090457848181518110151561086857fe5b9060200101517f010000000000000000000000000000000000000000000000000000000000000090047f01000000000000000000000000000000000000000000000000000000000000000283838060010194508151811015156108c757fe5b9060200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508080600101915050610851565b83965050505050505092915050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061095457805160ff1916838001178555610982565b82800160010185558215610982579182015b82811115610981578251825591602001919060010190610966565b5b50905061098f9190610993565b5090565b6109b591905b808211156109b1576000816000905550600101610999565b5090565b90565b600082601f83011215156109cb57600080fd5b81356109de6109d982610b6a565b610b3d565b915080825260208301602083018583830111156109fa57600080fd5b610a05838284610bad565b50505092915050565b600060208284031215610a2057600080fd5b600082013567ffffffffffffffff811115610a3a57600080fd5b610a46848285016109b8565b91505092915050565b60008060408385031215610a6257600080fd5b600083013567ffffffffffffffff811115610a7c57600080fd5b610a88858286016109b8565b925050602083013567ffffffffffffffff811115610aa557600080fd5b610ab1858286016109b8565b9150509250929050565b610ac481610ba1565b82525050565b6000610ad582610b96565b808452610ae9816020860160208601610bbc565b610af281610bef565b602085010191505092915050565b6000602082019050610b156000830184610abb565b92915050565b60006020820190508181036000830152610b358184610aca565b905092915050565b6000604051905081810181811067ffffffffffffffff82111715610b6057600080fd5b8060405250919050565b600067ffffffffffffffff821115610b8157600080fd5b601f19601f8301169050602081019050919050565b600081519050919050565b60008115159050919050565b82818337600083830152505050565b60005b83811015610bda578082015181840152602081019050610bbf565b83811115610be9576000848401525b50505050565b6000601f19601f83011690509190505600a265627a7a7230582091dbe6271b7f0a4119f689d262fb00022d0d1fed67be8356c463eaea3ee244e96c6578706572696d656e74616cf50037";
        String contract_name = "crud";
        //部署合约
        AjaxResult ajaxResult2 = EthPeer.deployContract(chain, fromAddress, fromkeystore, reqGasLimit, reqGasPrice, byteCode, "", contract_name);
        System.out.println("部署合约");
        System.out.println(JSONUtil.toJsonStr(ajaxResult2));*/


//        System.err.println(ajaxResult.getMessage());
//        String contractAddress1 = ajaxResult.getMessage();
//
//        ajaxResult = uploadChain(chain, contractAddress,  key, value);
//
//        System.out.println(ajaxResult.getMessage());

//
//        ajaxResult = startChain(chainName, chain,"hyz");
//        System.out.println(JSONUtil.toJsonStr(ajaxResult));
//
//        System.out.println(ajaxResult.getMessage());
////
//        for (int i = 0; i < 5; i++) {
//            String blockNumber = getBlockNumber();
//            System.out.println(blockNumber);
//            Thread.sleep(1000l);
//        }


//        System.out.println(JSONUtil.toJsonStr(ajaxResult));

//        getBlockNumber();
//        String contractAddress = "0x0abcc309c7d0a4af3924326b5e14578fec056644";
//        AjaxResult ajaxResult = getDataByChain(chain, contractAddress, address, keyStore,key);
//        AjaxResult ajaxResult = uploadChain(chain, contractAddress, address, keyStore, key, value);
        ajaxResult = getAllDataByChain(chain, contractAddress);
        System.out.println(ajaxResult.getMessage());
        System.out.println(ajaxResult.getData());

        JSONObject jsonObject = JSONUtil.parseObj(ajaxResult.getData());
        Set<String> set = jsonObject.keySet();
        for (String str : set) {
            String s = jsonObject.get(str).toString();
            System.out.println(s);
//            System.out.println(new String(Base64.getDecoder().decode(s)));
        }

    }


    public static String getContractAddress(Web3j web3j, String hash) throws Exception {
//        log.info("获取合约地址！");
        EthGetTransactionReceipt transactionReceipt = web3j.ethGetTransactionReceipt(hash).send();
        if (transactionReceipt.getResult() != null) {
            String contractAddress = transactionReceipt.getTransactionReceipt().get().getContractAddress();
            return contractAddress;
        } else {
            Thread.sleep(1000l);
            return getContractAddress(web3j, hash);
        }
    }


    /**
     * 主节点创建并启动链
     *
     * @return
     */
    public static AjaxResult creatChainAndStart(String chainId, String chainName, String creatName) throws Exception {

        String fromAddress = "0xb80377b5e52a16b317fd5f61e10ec0d1e8ee05e3";
        String fromkeystore = "{\"address\":\"b80377b5e52a16b317fd5f61e10ec0d1e8ee05e3\",\"id\":\"656a6015-6c53-4357-bc3b-e962d9e67879\",\"version\":3,\"crypto\":{\"cipher\":\"aes-128-ctr\",\"ciphertext\":\"06607e3e0128636c7bf9e0d8d518f451d4d5f3ed3f0f891e3d049236fc0df68f\",\"cipherparams\":{\"iv\":\"a42f13ef35debcbe81e266889a546c38\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":4096,\"p\":6,\"r\":8,\"salt\":\"a6020a1bd769e724e0113f108f7278b70eeca952e4e3887adae7bc2bc1ac5d1c\"},\"mac\":\"7959347fd7f15b93c2c65e49946074341dd52182a80035f54ba56e3c851a952c\"}}";


        Map map = new HashMap();
        map.put("peerIp", "127.0.0.1");
        map.put("chainId", chainId);
        map.put("chainName", chainName);
        map.put("difficulty", "1");
        map.put("gaslimit", "4294967295");
        map.put("extradata", fromAddress);
        map.put("alloc", "{'" + fromAddress + "':'300000000000000000'}");
        map.put("address", fromAddress);
        map.put("keystore", fromkeystore);
        map.put("creatName", creatName);
        //新建并启动链
        AjaxResult ethereumChain = EthPeer.createEthereumChain(map);
        System.out.println("创建启动链");
        System.out.println(JSONUtil.toJsonStr(ethereumChain));

//        Thread.sleep(1000l);

        if ("1".equals(ethereumChain.getCode())) {
            String reqGasLimit = "30000000";
            String reqGasPrice = "10";
            String byteCode = "608060405234801561001057600080fd5b50610ed4806100206000396000f300608060405260043610610078576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806353ed51431461007d57806364977dc8146100a8578063693ec85e146100d3578063962939b814610110578063bb5b27e11461014d578063f4c84d191461018a575b600080fd5b34801561008957600080fd5b506100926101c7565b60405161009f9190610d59565b60405180910390f35b3480156100b457600080fd5b506100bd6105d2565b6040516100ca9190610d9d565b60405180910390f35b3480156100df57600080fd5b506100fa60048036036100f59190810190610bde565b6105df565b6040516101079190610d7b565b60405180910390f35b34801561011c57600080fd5b5061013760048036036101329190810190610c1f565b6106ec565b6040516101449190610d3e565b60405180910390f35b34801561015957600080fd5b50610174600480360361016f9190810190610c8b565b6107b7565b6040516101819190610d7b565b60405180910390f35b34801561019657600080fd5b506101b160048036036101ac9190810190610c1f565b610872565b6040516101be9190610d3e565b60405180910390f35b60608060008060006040805190810160405280600181526020017f7b000000000000000000000000000000000000000000000000000000000000008152509350600092505b6001805490508310156105875760018381548110151561022857fe5b90600052602060002001915060008260405180828054600181600116156101000203166002900480156102925780601f10610270576101008083540402835291820191610292565b820191906000526020600020905b81548152906001019060200180831161027e575b5050915050908152602001604051809103902090506102e6846040805190810160405280600181526020017f27000000000000000000000000000000000000000000000000000000000000008152506108fe565b935061038b84838054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156103815780601f1061035657610100808354040283529160200191610381565b820191906000526020600020905b81548152906001019060200180831161036457829003601f168201915b50505050506108fe565b93506103cc846040805190810160405280600381526020017f273a2700000000000000000000000000000000000000000000000000000000008152506108fe565b93506104e18460008460405180828054600181600116156101000203166002900480156104305780601f1061040e576101008083540402835291820191610430565b820191906000526020600020905b81548152906001019060200180831161041c575b505091505090815260200160405180910390208054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156104d75780601f106104ac576101008083540402835291602001916104d7565b820191906000526020600020905b8154815290600101906020018083116104ba57829003601f168201915b50505050506108fe565b9350600180805490500383101561053857610531846040805190810160405280600281526020017f272c0000000000000000000000000000000000000000000000000000000000008152506108fe565b935061057a565b610577846040805190810160405280600181526020017f27000000000000000000000000000000000000000000000000000000000000008152506108fe565b93505b828060010193505061020c565b6105c6846040805190810160405280600181526020017f7d000000000000000000000000000000000000000000000000000000000000008152506108fe565b93508394505050505090565b6000600180549050905090565b60606000826040518082805190602001908083835b60208310151561061957805182526020820191506020810190506020830392506105f4565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405180910390208054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156106e05780601f106106b5576101008083540402835291602001916106e0565b820191906000526020600020905b8154815290600101906020018083116106c357829003601f168201915b50505050509050919050565b6000816000846040518082805190602001908083835b6020831015156107275780518252602082019150602081019050602083039250610702565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020908051906020019061076d929190610acf565b5060018390806001815401808255809150509060018203906000526020600020016000909192909190915090805190602001906107ab929190610acf565b50506001905092915050565b60606001828154811015156107c857fe5b906000526020600020018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156108665780601f1061083b57610100808354040283529160200191610866565b820191906000526020600020905b81548152906001019060200180831161084957829003601f168201915b50505050509050919050565b6000816000846040518082805190602001908083835b6020831015156108ad5780518252602082019150602081019050602083039250610888565b6001836020036101000a038019825116818451168082178552505050505050905001915050908152602001604051809103902090805190602001906108f3929190610acf565b506001905092915050565b606080606080606060008088955087945084518651016040519080825280601f01601f1916602001820160405280156109465781602001602082028038833980820191505090505b50935083925060009150600090505b8551811015610a0857858181518110151561096c57fe5b9060200101517f010000000000000000000000000000000000000000000000000000000000000090047f01000000000000000000000000000000000000000000000000000000000000000283838060010194508151811015156109cb57fe5b9060200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508080600101915050610955565b600090505b8451811015610ac0578481815181101515610a2457fe5b9060200101517f010000000000000000000000000000000000000000000000000000000000000090047f0100000000000000000000000000000000000000000000000000000000000000028383806001019450815181101515610a8357fe5b9060200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508080600101915050610a0d565b83965050505050505092915050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10610b1057805160ff1916838001178555610b3e565b82800160010185558215610b3e579182015b82811115610b3d578251825591602001919060010190610b22565b5b509050610b4b9190610b4f565b5090565b610b7191905b80821115610b6d576000816000905550600101610b55565b5090565b90565b600082601f8301121515610b8757600080fd5b8135610b9a610b9582610de5565b610db8565b91508082526020830160208301858383011115610bb657600080fd5b610bc1838284610e47565b50505092915050565b6000610bd68235610e3d565b905092915050565b600060208284031215610bf057600080fd5b600082013567ffffffffffffffff811115610c0a57600080fd5b610c1684828501610b74565b91505092915050565b60008060408385031215610c3257600080fd5b600083013567ffffffffffffffff811115610c4c57600080fd5b610c5885828601610b74565b925050602083013567ffffffffffffffff811115610c7557600080fd5b610c8185828601610b74565b9150509250929050565b600060208284031215610c9d57600080fd5b6000610cab84828501610bca565b91505092915050565b610cbd81610e27565b82525050565b6000610cce82610e11565b808452610ce2816020860160208601610e56565b610ceb81610e89565b602085010191505092915050565b6000610d0482610e1c565b808452610d18816020860160208601610e56565b610d2181610e89565b602085010191505092915050565b610d3881610e33565b82525050565b6000602082019050610d536000830184610cb4565b92915050565b60006020820190508181036000830152610d738184610cc3565b905092915050565b60006020820190508181036000830152610d958184610cf9565b905092915050565b6000602082019050610db26000830184610d2f565b92915050565b6000604051905081810181811067ffffffffffffffff82111715610ddb57600080fd5b8060405250919050565b600067ffffffffffffffff821115610dfc57600080fd5b601f19601f8301169050602081019050919050565b600081519050919050565b600081519050919050565b60008115159050919050565b6000819050919050565b6000819050919050565b82818337600083830152505050565b60005b83811015610e74578082015181840152602081019050610e59565b83811115610e83576000848401525b50505050565b6000601f19601f83011690509190505600a265627a7a723058206b2439de9d3e911aa84e6c5c5470709c7555de57c45a90eadc3381779161323e6c6578706572696d656e74616cf50037";
            String contract_name = "crud";
            //部署合约
            AjaxResult ajaxResult2 = EthPeer.deployContract(chainId, fromAddress, fromkeystore, reqGasLimit, reqGasPrice, byteCode, "", contract_name);
            System.out.println("部署合约");
            System.out.println(JSONUtil.toJsonStr(ajaxResult2));
            if ("1".equals(ajaxResult2.getCode())) {
                return ajaxResult2;
            } else {
                return ajaxResult2;
            }

        }

        return ethereumChain;
    }

    /**
     * 加入网络创建并启动链
     *
     * @return
     */
    public static AjaxResult creatChainAndStart1(String chainId, String chainName,String creatName) throws Exception {

        String fromAddress = "0xb80377b5e52a16b317fd5f61e10ec0d1e8ee05e3";
        String fromkeystore = "{\"address\":\"b80377b5e52a16b317fd5f61e10ec0d1e8ee05e3\",\"id\":\"656a6015-6c53-4357-bc3b-e962d9e67879\",\"version\":3,\"crypto\":{\"cipher\":\"aes-128-ctr\",\"ciphertext\":\"06607e3e0128636c7bf9e0d8d518f451d4d5f3ed3f0f891e3d049236fc0df68f\",\"cipherparams\":{\"iv\":\"a42f13ef35debcbe81e266889a546c38\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":4096,\"p\":6,\"r\":8,\"salt\":\"a6020a1bd769e724e0113f108f7278b70eeca952e4e3887adae7bc2bc1ac5d1c\"},\"mac\":\"7959347fd7f15b93c2c65e49946074341dd52182a80035f54ba56e3c851a952c\"}}";

        Map map = new HashMap();
        map.put("peerIp", "127.0.0.1");
        map.put("chainId", chainId);
        map.put("chainName", chainName);
        map.put("difficulty", "1");
        map.put("gaslimit", "4294967295");
        map.put("extradata", fromAddress);
        map.put("alloc", "{'" + fromAddress + "':'300000000000000000'}");
        map.put("address", fromAddress);
        map.put("keystore", fromkeystore);
        map.put("creatName", creatName);
        //新建并启动链
        AjaxResult ethereumChain = EthPeer.createEthereumChainNoMiner(map);
//        AjaxResult ajaxResult1 = EthWallet.uploadAndUnlock(chainName, address, keyStore);

        return ethereumChain;
    }


    /**
     * 链已经创建
     * 启动链 挖矿
     *
     * @param chainName
     * @param chainId
     * @return
     */
    public static AjaxResult startChain(String chainName, String chainId ,String creatName) throws Exception {
        String fromAddress = "0xb80377b5e52a16b317fd5f61e10ec0d1e8ee05e3";
        String fromkeystore = "{\"address\":\"b80377b5e52a16b317fd5f61e10ec0d1e8ee05e3\",\"id\":\"656a6015-6c53-4357-bc3b-e962d9e67879\",\"version\":3,\"crypto\":{\"cipher\":\"aes-128-ctr\",\"ciphertext\":\"06607e3e0128636c7bf9e0d8d518f451d4d5f3ed3f0f891e3d049236fc0df68f\",\"cipherparams\":{\"iv\":\"a42f13ef35debcbe81e266889a546c38\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":4096,\"p\":6,\"r\":8,\"salt\":\"a6020a1bd769e724e0113f108f7278b70eeca952e4e3887adae7bc2bc1ac5d1c\"},\"mac\":\"7959347fd7f15b93c2c65e49946074341dd52182a80035f54ba56e3c851a952c\"}}";

        AjaxResult ru = new AjaxResult();
        boolean b = EthPeer.startChain(chainName, chainId, fromAddress,creatName);
        if (b) {

            /*try {
                ServerSocket server = new ServerSocket(8545);
                ru.setCode("0");
                ru.setMessage("链启动失败");
            }catch (IOException e) {
                ru.setCode("1");
                ru.setMessage("链启动成功");
            }*/

//            String s1 = EthPeer.checkChainValid2("127.0.0.1");
//            if (s1 != null) {
//                ru.setCode("1");
//                ru.setMessage("链启动成功");
//
//            } else {
//                ru.setCode("0");
//                ru.setMessage("链启动失败");
//            }
        } else {
            ru.setCode("0");
            ru.setMessage("链启动失败");
        }
        return ru;
    }

    /**
     * 加入网络创建并启动链
     *
     * @return
     */
    public static AjaxResult creatChainAndStart1(String chainId, String chainName) throws Exception {

        String fromAddress = "0xb80377b5e52a16b317fd5f61e10ec0d1e8ee05e3";
        String fromkeystore = "{\"address\":\"b80377b5e52a16b317fd5f61e10ec0d1e8ee05e3\",\"id\":\"656a6015-6c53-4357-bc3b-e962d9e67879\",\"version\":3,\"crypto\":{\"cipher\":\"aes-128-ctr\",\"ciphertext\":\"06607e3e0128636c7bf9e0d8d518f451d4d5f3ed3f0f891e3d049236fc0df68f\",\"cipherparams\":{\"iv\":\"a42f13ef35debcbe81e266889a546c38\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":4096,\"p\":6,\"r\":8,\"salt\":\"a6020a1bd769e724e0113f108f7278b70eeca952e4e3887adae7bc2bc1ac5d1c\"},\"mac\":\"7959347fd7f15b93c2c65e49946074341dd52182a80035f54ba56e3c851a952c\"}}";

        Map map = new HashMap();
        map.put("peerIp", "127.0.0.1");
        map.put("chainId", chainId);
        map.put("chainName", chainName);
        map.put("difficulty", "1");
        map.put("gaslimit", "4294967295");
        map.put("extradata", fromAddress);
        map.put("alloc", "{'" + fromAddress + "':'300000000000000000'}");
        map.put("address", fromAddress);
        map.put("keystore", fromkeystore);
        //新建并启动链
        AjaxResult ethereumChain = EthPeer.createEthereumChainNoMiner(map);
//        AjaxResult ajaxResult1 = EthWallet.uploadAndUnlock(chainName, address, keyStore);

        return ethereumChain;
    }




    /**
     * 启动链，不挖矿
     *
     * @param chainName
     * @param chainId
     * @return
     */
    public static AjaxResult startChain1(String chainName, String chainId,String creatName) throws Exception {
        AjaxResult ru = new AjaxResult();
        boolean b = EthPeer.startChainNoMiner(chainName, chainId,creatName);
        if (b) {
//            String s1 = EthPeer.checkChainValid2("127.0.0.1");
//            if (s1 != null) {
//                ru.setCode("1");
//                ru.setMessage("链测试启动成功");
//            } else {
//                ru.setCode("0");
//                ru.setMessage("链测试启动失败");
//            }
        } else {
            ru.setCode("0");
            ru.setMessage("链测试启动失败");
        }
        return ru;
    }

    /**
     * 数据上链
     *
     * @param chainId         //链ID
     * @param contractAddress //合约地址
     * @param key             //数据标识
     * @param value           //上链数据
     * @return
     * @throws Exception
     */
    public static AjaxResult uploadChain(String chainId, String contractAddress, String key, String value) throws Exception {
        String type = "0";//0-产生交易；1-不产生交易
        String functionName = "save";
//        String s = HexUtil.encodeHexStr(value);
        List<Map<String, String>> list = new ArrayList<>();
        Map<String, String> map1 = new HashMap<>();
        map1.put("type", "string");
        map1.put("value", key);
        Map<String, String> map2 = new HashMap<>();
        map2.put("type", "string");
        map2.put("value", value);
        list.add(map1);
        list.add(map2);
        String arrString = JSONUtil.toJsonStr(list);
        //调用合约
        chainId = (Integer.valueOf(chainId)) + "";
        log.info("上链数据Key："+key);
        log.info("上链数据："+value);
        AjaxResult ajaxResult = EthPeer.ethCallContract(chainId, type, contractAddress, functionName, arrString);
        log.info("上链返回数据："+JSONUtil.toJsonStr(ajaxResult));
        return ajaxResult;
    }


    /**
     * 更新上链数据
     *
     * @param chainId         //链ID
     * @param contractAddress //合约地址
     * @param key             //数据标识
     * @param value           //上链数据
     * @return
     * @throws Exception
     */
    public static AjaxResult updateChain(String chainId, String contractAddress, String key, String value) throws Exception {
        String type = "0";//0-产生交易；1-不产生交易
        String functionName = "update";
//        String s = HexUtil.encodeHexStr(value);
        List<Map<String, String>> list = new ArrayList<>();
        Map<String, String> map1 = new HashMap<>();
        map1.put("type", "string");
        map1.put("value", key);
        Map<String, String> map2 = new HashMap<>();
        map2.put("type", "string");
        map2.put("value", value);
        list.add(map1);
        list.add(map2);
        String arrString = JSONUtil.toJsonStr(list);
        //调用合约
        chainId = (Integer.valueOf(chainId)) + "";
        log.info("上链数据Key："+key);
        log.info("上链数据："+value);
        AjaxResult ajaxResult = EthPeer.ethCallContract(chainId, type, contractAddress, functionName, arrString);
        log.info("上链返回数据："+JSONUtil.toJsonStr(ajaxResult));
        return ajaxResult;
    }

    /**
     * 从链上查询数据
     *
     * @param chainId         //链id
     * @param contractAddress //合约地址
     * @param address         //钱包地址
     * @param keystore
     * @param key
     * @return
     * @throws Exception
     */
    public static AjaxResult getDataByChain(String chainId, String contractAddress, String address, String keystore, String key) throws Exception {
        AjaxResult ru = new AjaxResult();
        String type = "1";//0-产生交易；1-不产生交易
        String functionName = "get";
        List<Map<String, String>> list = new ArrayList<>();
        Map<String, String> map1 = new HashMap<>();
        map1.put("type", "string");
        map1.put("value", key);
        list.add(map1);
        String arrString = JSONUtil.toJsonStr(list);
        //调用合约
        chainId = (Integer.valueOf(chainId) + 1) + "";
        AjaxResult ajaxResult = EthPeer.ethCallContract(chainId, type, contractAddress, functionName, arrString);
        if ("1".equals(ajaxResult.getCode())) {
            String message = ajaxResult.getMessage();
            message = message.substring(130, message.length());
            byte[] bytes = Numeric.hexStringToByteArray(message);
            String pt = new String(bytes).trim();
/*//            ********)

            System.out.println(pt);
            if (!isBase64(pt)) {
                pt = pt.substring(1, pt.length());
            }*/
            System.out.println(pt);
            ru.setCode("1");
            ru.setData(pt);
            ru.setMessage("查询成功");
            return ru;
        }
        return ajaxResult;
    }
    /**
     * 从链上查询数据
     *
     * @param chainId         //链id
     * @param contractAddress //合约地址
     * @return
     * @throws Exception
     */
    public static AjaxResult getKeyListLengthByChain(String chainId, String contractAddress) throws Exception {
        AjaxResult ru = new AjaxResult();
        String type = "1";//0-产生交易；1-不产生交易
        String functionName = "getKeyListLength";
        List<Map<String, String>> list = new ArrayList<>();
        Map<String, String> map1 = new HashMap<>();
        /*map1.put("type", "string");
        map1.put("value", key);*/
        list.add(map1);
        String arrString = JSONUtil.toJsonStr(list);
        //调用合约
        chainId = (Integer.valueOf(chainId) + 1) + "";
        AjaxResult ajaxResult = EthPeer.ethCallContract(chainId, type, contractAddress, functionName, arrString);
        if ("1".equals(ajaxResult.getCode())) {
            String message = ajaxResult.getMessage();
            message = message.substring(2, message.length());
            Long aLong = Long.valueOf(message, 16);
//            byte[] bytes = Numeric.hexStringToByteArray(message);
//            String pt = new String(bytes).trim();
/*//            ********)

            System.out.println(pt);
            if (!isBase64(pt)) {
                pt = pt.substring(1, pt.length());
            }*/
            System.out.println(aLong);
            ru.setCode("1");
            ru.setData(aLong);
            ru.setMessage("查询成功");
            return ru;
        }
        return ajaxResult;
    }

    /**
     * 从链上查询数据
     *
     * @param chainId         //链id
     * @param contractAddress //合约地址
     * @param num
     * @return
     * @throws Exception
     */
    public static AjaxResult getKeyByChain(String chainId, String contractAddress,String num) throws Exception {
        AjaxResult ru = new AjaxResult();
        String type = "1";//0-产生交易；1-不产生交易
        String functionName = "getKey";
        List<Map<String, String>> list = new ArrayList<>();
        Map<String, String> map1 = new HashMap<>();
        map1.put("type", "uint");
        map1.put("value", num);
        list.add(map1);
        String arrString = JSONUtil.toJsonStr(list);
        //调用合约
        chainId = (Integer.valueOf(chainId) + 1) + "";
        AjaxResult ajaxResult = EthPeer.ethCallContract(chainId, type, contractAddress, functionName, arrString);
        if ("1".equals(ajaxResult.getCode())) {
            String message = ajaxResult.getMessage();
            message = message.substring(130, message.length());
            byte[] bytes = Numeric.hexStringToByteArray(message);
            String pt = new String(bytes).trim();
/*//            ********)

            System.out.println(pt);
            if (!isBase64(pt)) {
                pt = pt.substring(1, pt.length());
            }*/
            System.out.println(pt);
            ru.setCode("1");
            ru.setData(pt);
            ru.setMessage("查询成功");
            return ru;
        }
        return ajaxResult;
    }

    public static boolean isBase64(String str) {
        if (str == null || str.trim().length() == 0) {
            return false;
        } else {
            if (str.length() % 4 != 0) {
                return false;
            }
            char[] charA = str.toCharArray();
            for (char c : charA) {
                if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '+' || c == '/' || c == '=') {
                    continue;
                } else {
                    return false;
                }
            }
            return true;
        }
    }

    /**
     * 从链上查询数据
     *
     * @param chainId         //链id
     * @param contractAddress //合约地址
     * @return
     * @throws Exception
     */
    public static AjaxResult getAllDataByChain(String chainId, String contractAddress) throws Exception {
        AjaxResult ru = new AjaxResult();
        String type = "1";//0-产生交易；1-不产生交易
        String functionName = "getAll";
        List<Map<String, String>> list = new ArrayList<>();
        Map<String, String> map1 = new HashMap<>();
//        map1.put("type", "string");
//        map1.put("value", key);
        list.add(map1);
        String arrString = JSONUtil.toJsonStr(list);
        //调用合约
        AjaxResult ajaxResult = EthPeer.ethCallContract(chainId, type, contractAddress, functionName, arrString);
        if ("1".equals(ajaxResult.getCode())) {
            String message = ajaxResult.getMessage();
            message = message.substring(130, message.length());
            byte[] bytes = Numeric.hexStringToByteArray(message);
            String pt = new String(bytes).trim();
            ru.setCode("1");
            ru.setData(pt);
            ru.setMessage("查询成功");
            return ru;
        }
        return ajaxResult;
    }


    /**
     * 开启挖矿
     *
     * @return
     * @throws Exception
     */
    public static AjaxResult startMine() throws Exception {
        String fromAddress = "0xb80377b5e52a16b317fd5f61e10ec0d1e8ee05e3";
        log.info("开启挖矿");
        return EthPeer.startMine(fromAddress);
    }

    /**
     * 关闭挖矿
     *
     * @return
     * @throws Exception
     */
    public static AjaxResult stopMine() throws Exception {
        log.info("停止挖矿");
        return EthPeer.stopMine();
    }

    public static String getBlockNumber() {
        String ip = "127.0.0.1";
        return getBlockNumber(ip);
    }

    public static String getBlockNumber(String ip) {
        Web3j web3j = Web3j.build(new HttpService("http://" + ip + ":8545"));
        try {
            Request<?, EthBlockNumber> ethBlockNumberRequest = web3j.ethBlockNumber();
            BigInteger blockNumber = ethBlockNumberRequest.send().getBlockNumber();
//            System.out.println(blockNumber.toString());
            return blockNumber.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }




    /**
     * 转账
     */
    /**
     * eth转账
     * 1.检查必填参数是否传入，否则会提示某项参数缺失
     * 2.gasPrice为可选参数。如果未传入，此接口默认取当前网络平均值。建议不传，使用默认值。
     * gasPrice单位为Gwei
     * 3.传入的ETH单位为Ether，此接口会自动进行转换为Wei。例如，转账1eth，
     * 则传入1，而非1000000000000000000
     * 4.此接口会检测转出方是否有足够ETH进行转账，否则会提示ETH不足
     * 5.当接口返回交易hash时，此交易的状态即为success，不需要再通过查询获取交易状态
     * 6.此接口会在交易状态为success时才返回交易hash，耗时取决于当前以太坊网络状况，
     *
     * <p>
     * <p>
     * 参数:
     * 1.transferAddress: 转账方地址
     * 2.receiverAddress: 接收方地址
     * 3.privateKey: 私钥
     * 4.num: eth数量
     * 5.gasPrice: (可选)燃料费单价
     * <p>
     * 返回:1.data: 交易成功的hash
     */
    /*public static AjaxResult transferEth(String fromAddress,
                                         String toAddress,
                                         String chainId,
                                         String value,
                                         String keystore
    ) throws Exception {
        AjaxResult ru = new AjaxResult();


        Web3j web3jUtil = Web3j.build(new HttpService("http://127.0.0.1:8545"));

        //2.检查非必要参数

        //nonce
        BigInteger nonce = getTransactionNonce(fromAddress, web3jUtil);

        //gaslimit,默认是21000
        BigInteger gasLimit = BigInteger.valueOf(210000);

//        if (!"".equals(gasLimits)) {
//            gasLimit = new BigInteger(gasLimits);
//        }
        // gasLimit = Contract.GAS_LIMIT;
        //gasprice-如果没有传入gasprice就自动获取
        BigInteger gasPrice = Convert.toWei(BigDecimal.valueOf(2), Convert.Unit.GWEI).toBigInteger();

//        if (!"".equals(gasprices)) {
//            gasPrice = Convert.toWei(new BigDecimal(gasprices), Convert.Unit.GWEI).toBigInteger();
//        }

        //value
        BigInteger weiValue = Convert.toWei(new BigDecimal(value), Convert.Unit.ETHER).toBigInteger();
        //判断转账方是否余额足够
        BigInteger balance = web3jUtil.ethGetBalance(fromAddress, DefaultBlockParameter.valueOf("Latest")).send().getBalance();
        //两个wei 进行比较
        if (weiValue.compareTo(balance) == 1) {
            //转账金额大于余额
            ru.setMessage("余额不足");
            return ru;
        }

        EthWallet.EthHDWallet wallet = EthWallet.decryptWalletByKeystore(keystore);
        String privateKey = "";
        privateKey = wallet.privateKey;
        //data--备注内容
        String data = "";
        //对交易进行签名
        String signedData = null;
        byte bchainId = (byte) Integer.parseInt(chainId);
        signedData = signTransaction(nonce, gasPrice, gasLimit, toAddress, weiValue, data, bchainId, privateKey);
        //同步异步
        if (signedData != null) {
            //发送交易
            EthSendTransaction ethSendTransaction = null;
            try {
                ethSendTransaction = web3jUtil.ethSendRawTransaction(signedData).sendAsync().get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
            if (ethSendTransaction.hasError()) {
                ru.setCode("0");
                ru.setMessage("交易失败:" + ethSendTransaction.getError().getMessage());
            } else {
                ru.setCode("1");
                String transactionHash = ethSendTransaction.getTransactionHash();
//                    ru.setMessage("交易hash:" + "" + transactionHash);
                ru.setMessage(transactionHash);
            }
        } else {
            ru.setCode("0");
            ru.setMessage("交易签名失败，传参有误");
        }
        return ru;
    }*/

    /**
     * 获取账号交易次数 nonce
     *
     * @param address 钱包地址
     * @return nonce
     */
    private static BigInteger getTransactionNonce(String address, Web3j web3jUtil) {
        BigInteger nonce = BigInteger.ZERO;
        try {
            EthGetTransactionCount ethGetTransactionCount = web3jUtil.ethGetTransactionCount(address, DefaultBlockParameterName.PENDING).send();
            nonce = ethGetTransactionCount.getTransactionCount();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return nonce;
    }


    /**
     * 签名交易
     */
    public static String signTransaction(BigInteger nonce, BigInteger gasPrice, BigInteger gasLimit, String to,
                                         BigInteger value, String data, byte chainId, String privateKey) throws IOException {
        byte[] signedMessage;
        RawTransaction rawTransaction = RawTransaction.createTransaction(
                nonce,
                gasPrice,
                gasLimit,
                to,
                value,
                data);
        if (privateKey.startsWith("0x")) {
            privateKey = privateKey.substring(2);
        }
        ECKeyPair ecKeyPair = ECKeyPair.create(new BigInteger(privateKey, 16));
        Credentials credentials = Credentials.create(ecKeyPair);

        //如果是合理的chainId 对chainId进行签名
        if (chainId > ChainId.NONE) {

            signedMessage = TransactionEncoder.signMessage(rawTransaction, chainId, credentials);
        } else {
            signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials);
        }


        String hexValue = Numeric.toHexString(signedMessage);
        return hexValue;
    }


}
